#include "app_bt.h"
#include "log/log.h"
#include "string.h"
#include "log/log.h"
#include <unistd.h>
#include "app_serial.h"

static int bt_init_config(Device_t *device)
{
    // 初始化串口  9600 阻塞
    app_serial_init(device);

    // 修改串口为非阻塞
    app_serial_setBlock(device, 0);
    app_serial_flush(device);

    // 判断蓝牙是否可用，如果可用， 说明蓝牙波特率是9600， 修改波特率/名称/NETID/MADDR, 重启蓝牙
    if (app_bt_status(device) == 0)
    {
        app_bt_setBaudRate(device, BT_BR_115200);
        app_bt_rename(device, "lliron");
        app_bt_reset(device);
        // 等待蓝牙重启完成
        sleep(2);
    }

    // 当前蓝牙的波特率是115200, 而串口是9600, 所以需要修改串口波特率115200
    app_serial_setBaudRate(device, BR_115200);
    app_serial_flush(device);

    // 再次判断蓝牙是否可用，如果不可用，错误退出，蓝牙初始化失败
    if (app_bt_status(device) != 0)
    {
        log_error("蓝牙初始化失败");
        return -1;
    }
    app_bt_setNetId(device, "5565");
    app_bt_setMaddr(device, "dbaa");

    // 将串口改阻塞模式
    app_serial_setBlock(device, 1);
    app_serial_flush(device);

    log_debug("蓝牙初始化成功");
    return 0;
}

int app_bt_init(Device_t *device)
{
    device->read_post_fun = app_bt_postRead;
    device->write_pre_fun = app_bt_preWrite;

    // 蓝牙初始化
    return bt_init_config(device);
    return 0;
}

/*
    预处理数据 写入蓝牙模块之前
    将数据做如下变换
    1 2 3 xx abc ==> AT+MESH XX abc \r\n
*/
int app_bt_preWrite(char *data, int len)
{
    // 数据最少6字节
    if (len < 6)
    {
        log_error("数据长度不够");
        return -1;
    }
    // 根据预处理计算蓝牙数据的长度 提前创建好缓存数组
    // 这里12是固定长度 AT+MESH + id两位 + '\r\n'
    int bt_len = 12 + data[2];
    // 创建缓存数组
    char bt_buf[bt_len];

    // 填充数据
    memcpy(bt_buf, "AT+MESH", 8);
    // ig
    memcpy(bt_buf + 8, data + 3, 2);
    // msg
    memcpy(bt_buf + 10, data + 5, data[2]);
    // \r\n
    memcpy(bt_buf + 10 + data[2], "\r\n", 2);

    // 清空data
    memset(data, 0, len);
    // 拷贝数据
    memcpy(data, bt_buf, bt_len);

    return bt_len;
}

/*
    预处理数据 从蓝牙模块读出之后
    f1 dd : 固定的头部
    07： 之后数据的长度（5-16之间）
    23 23：对端（发送方）的MADDR
    ff ff: 我的MADDR或ffff(群发)
    41 42 43：发送的数据
    将数据做如下变换
    f1 dd 07 23 23 ff ff 41 42 43 ==> 1 2 3 XX abc
*/
static char post_read_buf[1024];          // 用来缓存数据
static int post_read_len = 0;             // 缓存的长度
static char fix_header[2] = {0xf1, 0xdd}; // 固定头

static void remove_data(int num)
{
    memmove(post_read_buf, post_read_buf + num, post_read_len - num);
    post_read_len -= num;
}
int app_bt_postRead(char *data, int len)
{
    // 1.将数据缓存起来
    memcpy(post_read_buf + post_read_len, data, len);
    post_read_len += len;
    // 2.校验数据
    if (post_read_len < 8)
    {
        log_debug("数据长度不够 继续读取");
        return 0;
    }
    // 3.判断当前有没有完整的一帧数据
    int i;
    for (i = 0; i < post_read_len - 7; i++)
    {
        if (memcmp(post_read_buf + i, fix_header, 2) == 0)
        {
            log_debug("找到帧头");
            // 删除前面无用的数据
            if (i > 0)
            {
                remove_data(i);
            }
            // f1 dd 07 23 23 ff ff 41 42 43 第三位为后面数据的长度
            // 完整蓝牙数据的长度
            int bt_data_len = 3 + post_read_buf[2];
            // 如果缓存的数据长度小于完整的蓝牙数据长度 说明数据不完整
            log_debug("bt_data_len:%d,post_read_len:%d", bt_data_len, post_read_len);
            if (post_read_len < bt_data_len)
            {
                // 4.如果没有则继续等待下一帧数据
                log_debug("数据不完整 继续读取");
                return 0;
            }
            // 5.如果有完整数据，则处理数据
            // 这里说明读取到了完整的数据 将数据保存到data
            memset(data, 0, len);
            data[0] = 1;                                  // conn_type
            data[1] = 2;                                  // id_len
            data[2] = post_read_buf[2] - 4;               // msg_len
            memcpy(data + 3, post_read_buf + 3, 2);       // id
            memcpy(data + 5, post_read_buf + 7, data[2]); // msg

            // 删除已经处理过的蓝牙数据
            remove_data(bt_data_len);
            // 返回字符数组数据的长度
            return 3 + 2 + data[2];
        }
    }
    if (i > 0)
    {
        // 删除无用的数据
        remove_data(i);
    }
    return 0;
}

static int wait_ack(int fd)
{
    // 等待一定的时间（50ms）
    usleep(50 * 1000);
    // 从串口文件中读取4个字节数据，判断是否是OK\r\n
    char data_buf[4];
    read(fd, data_buf, 4);
    if (memcmp(data_buf, "OK\r\n", 4) != 0)
    {
        log_error("等待ack失败");
        return -1;
    }
    return 0;
}

int app_bt_status(Device_t *device)
{
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char *cmd = "AT\r\n";
    write(device->fd, cmd, strlen(cmd));

    // 等待ack
    return wait_ack(device->fd);
}

int app_bt_rename(Device_t *device, char *name)
{
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char cmd[20];
    sprintf(cmd, "AT+NAME%s\r\n", name);
    write(device->fd, cmd, strlen(cmd));

    // 等待ack
    return wait_ack(device->fd);
}

int app_bt_setBaudRate(Device_t *device, BT_BR baudRate)
{
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char cmd[20];
    sprintf(cmd, "AT+BAUD%c\r\n", baudRate);
    write(device->fd, cmd, strlen(cmd));

    // 等待ack
    return wait_ack(device->fd);
}

int app_bt_reset(Device_t *device)
{
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char *cmd = "AT+RESET\r\n";
    write(device->fd, cmd, strlen(cmd));

    // 等待ack
    return wait_ack(device->fd);
}

int app_bt_setNetId(Device_t *device, char *netId)
{
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char cmd[20];
    sprintf(cmd, "AT+NETID%s\r\n", netId);
    write(device->fd, cmd, strlen(cmd));

    // 等待ack
    return wait_ack(device->fd);
}

int app_bt_setMaddr(Device_t *device, char *maddr)
{
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char cmd[20];
    sprintf(cmd, "AT+MADDR%s\r\n", maddr);
    write(device->fd, cmd, strlen(cmd));

    // 等待ack
    return wait_ack(device->fd);
}
